import socket
import ipaddress
import threading
import json
import os
from robot_control import Base_Communicator


def is_valid_ip(ip_str):
    try:
        # 使用ipaddress库的ip_address方法尝试解析IP地址
        ipaddress.ip_address(ip_str)
        return True
    except ValueError:
        return False

CONFIG = {}
if os.path.exists("config.json"):
    with open("config.json", "r") as f:
        CONFIG:dict = json.load(f)
    if "RemoteIP" not in CONFIG.keys():
        CONFIG["RemoteIP"] = "0.0.0.0"
    if "Port" not in CONFIG.keys():
        CONFIG["Port"] = 8888
else:
    CONFIG["RemoteIP"] = "0.0.0.0"
    CONFIG["Port"] = 8888


def save_config():
    global CONFIG
    # 同步配置
    with open("config.json", 'w') as js_file:
        json.dump(CONFIG, js_file, indent=4)



# 本地IP和端口
# 获取本地主机名
HOSTNAME = socket.gethostname()
# 获取本地IP地址
LOCAL_IP = socket.gethostbyname(HOSTNAME)
LOCAL_PORT = CONFIG["Port"]
print(f"local IP:{LOCAL_IP}, local Port: {LOCAL_PORT}")
print(f"RemoteIP:{CONFIG['RemoteIP']}")
save_config()



def get_remote_ip_from_input(config:dict):
# 远程IP和端口（ESP32的IP和端口）
    while True:
        print(f"直接回车可填入上次连接的地址")
        remoteIP = input("输入机器人的IP地址: ")
        if is_valid_ip(remoteIP):
            print(f"\"{remoteIP}\" 是一个有效的IP地址")
            config["RemoteIP"] = remoteIP
            break
        elif remoteIP:
            print(f"\"{remoteIP}\" 不是一个有效的IP地址")
        else:
            remoteIP = config["RemoteIP"]
            if is_valid_ip(remoteIP):
                print(f"\"{remoteIP}\" 是一个有效的IP地址")
            break
    return remoteIP

# 监听UDP数据包的线程函数
def listen_thread(_sock:socket.socket, func):
    while True:
        # 从UDP套接字接收数据
        data, addr = _sock.recvfrom(1024)
        func(data)

def start_listen_sock(sock:socket.socket, func):
    '''启用一个线程后台监听网络信息, 传入`func(input:bytes)->None`'''
    listen_thread = threading.Thread(target=listen_thread, args=(sock, func))
    listen_thread.start()
    return listen_thread



class Udp_Communicator(Base_Communicator):
    def __init__(self, ip):
        global CONFIG
        self.ip = ip
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.bind((LOCAL_IP, CONFIG["Port"]))
        self.sock.setblocking(False)
        self.isOpen = True
        self.lock = threading.Lock()
        CONFIG["RemoteIP"] = self.ip
        save_config()
        print(f"{self.ip}:{CONFIG['Port']} start")
        self.write(f"$0 {LOCAL_IP}".encode())
    
    def __del__(self, *args):
        if self.isOpen:
            self.close()

    def start(self):
        if not self.isOpen:
            self.sock.bind((LOCAL_IP, CONFIG["Port"]))

    def close(self):
        self.lock.acquire()
        self.sock.close()
        self.lock.release()
        self.isOpen = False
        print(f"{LOCAL_IP}:{CONFIG['Port']} close")

    def write(self, bytes_: bytes) -> int:
        if self.isOpen:
            self.lock.acquire()
            self.sock.sendto(bytes_, (self.ip, LOCAL_PORT))
            self.lock.release()
            return len(bytes_)
        else:
            return 0

    def read(self, length: int=1024) -> bytes:
        try:
            data, addr = self.sock.recvfrom(length)
        except Exception as e:
            return None
        return data
    


if __name__ == "__main__":
    ...